﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Security.Cryptography;
using System.Windows.Forms;
using Urd.Packet;
using Urd.Common;
using Urd;
namespace Urd.Lab
{
    
    public class topmanager
    {
       // List<TcpClient> clients;
       //// List<NetworkStream> streams;
       // TcpListener listener;
       // Thread listenerthread,streamreadthread,streamwritethread,updatedebug;

       // public Dictionary<int,packet> recieved;
       // public Dictionary<int, packet> await;


       // public ListBox.ObjectCollection debugr;
       // public ListBox.ObjectCollection debugw;

       // packet work(packet p, cache c) 
       // {
       //     return new packet(Opcode.OK);
       // }

       // void listenerwork(object o)
       // {
       //     TcpListener l = (TcpListener)o;
       //     clients.Add(l.AcceptTcpClient());
       //     //streams.Add(c.GetStream());
       // }
       // void streamreadthreadwork() 
       // {
       //     int i = 0;
       //     foreach (TcpClient c in clients) 
       //     {
       //         byte [] buf = new byte[256];

       //         c.GetStream().Read(buf, 0, buf.Length);

       //         packet p = new packet(buf);

       //         recieved.Add(i, p);

       //         i++;
       //     }
       // }
       // void streamwritethreadwork() 
       // {
       //     foreach (KeyValuePair<int,packet> p in await) 
       //     {
       //         clients[p.Key].GetStream().Write(p.Value.Bytes, 0, p.Value.Bytes.Length);
       //     }
       // }


       // void updatedebugwork() 
       // {
       //     foreach (KeyValuePair<int, packet> p in recieved) 
       //     {
       //         debugr.Add(p.Value.debug);
       //     }

       //     foreach (KeyValuePair<int, packet> p in await)
       //     {
       //         debugw.Add(p.Value.debug);
       //     }
       //     Thread.Sleep(300);
       // }


       // public topman(ListBox r,ListBox a) 
       // {
       //     listener = new TcpListener(IPAddress.Any,1887);
       //     listener.Start();

       //     listenerthread = new Thread(new ParameterizedThreadStart(listenerwork));
       //     listenerthread.Start(listener);

       //     streamreadthread = new Thread(new ThreadStart(streamreadthreadwork));
       //     streamreadthread.Start();

       //     streamwritethread = new Thread(new ThreadStart(streamwritethreadwork));
       //     streamwritethread.Start();

       //     updatedebug = new Thread(new ThreadStart(updatedebugwork));
       //     updatedebug.Start();

       //     clients = new List<TcpClient>();

       //     recieved = new Dictionary<int, packet>();
       //     await = new Dictionary<int, packet>();

       //     debugr = new ListBox.ObjectCollection(r);
       //     debugw = new ListBox.ObjectCollection(a);

        class topmanworker : worker 
        {
            public override packet process(cache c, packet p)
            {
                packet ret;
                ret = new packet(opcode, Command.GetOK);
                object[] temp = c.Sql("select name,opcode,address,port from managers", true);
                string ss = "";
                foreach (object s in temp)
                {

                    ss+=s.ToString() + "|";
                }
                ret.Push(ss);
                cachedpacket = ret;
                return ret;
            }
        
            public topmanworker() 
            {
                opcode_to_accept = Opcode.ManagerInfo;
                name = "topmanager";
            }
        }
      //  public struct workerinfo 
        //{
        //    public string path;
        //    public string type;
        //    public string hash;
        //    public workerinfo(string path, string type, string hash) 
        //    {
        //        this.path = path;
        //        this.hash = hash;
        //        this.type = type;
        //    }
        //}
        
       // List<managerinfo> infos;
        async_cached_manager man;
        List<worker> workers;
        string path;
        bool started;
        public bool Started { get { return started; } }
        public topmanager(string workerspath) 
        {
            workers = new List<worker>();
            path = workerspath;
            
           managerinfo maninfo = new managerinfo(Opcode.ManagerInfo,1888,server.config.ipaddress,"topmanager","managers","managers");
           man = new async_cached_manager(maninfo, new topmanworker(),false);
           started = false;
            
        }
        public void start() 
        {
            man.start();
            started = true;
        }
        public void stop() 
        {
            man.stop();
            started = false;
        }
        public string[] info(string managername) 
        {
            List<string> list = new List<string>();
            object[] temp = man.Cache.Sql("select * from managers where name ='" + managername+"'",true);
            foreach(object o in temp)
            {
                list.Add(Convert.ToString(o));
            }
            return list.ToArray();
        }
        public managerinfo minfo(string managername)
        {
            managerinfo mret = new managerinfo();
            string[] ret = info(managername);
            if (ret.Length > 0)
            {
                mret.managername = ret[0];
                mret.address=IPAddress.Parse(ret[1]);
                mret.port = Int32.Parse(ret[2]);
                mret.able_to_accept = (Opcode)Enum.Parse(typeof(Opcode),ret[3]);
                mret.filename = ret[6];
                mret.tablename = ret[7];

            }
            else mret.managername = "null";
            return mret;
            
        }
        /// <summary>
        /// scan for plugins in plugin folder
        /// </summary>      
        public void scan() 
        {
            string[] paths = System.IO.Directory.GetFiles(this.path, "*.dll");


            foreach (string path in paths)
            {
                Assembly a = Assembly.LoadFrom(path);
                foreach (TypeInfo o in a.DefinedTypes)
                {
                    if (o.BaseType!=null&&o.BaseType.Name == "worker")
                    {
                        MD5Cng cng = new MD5Cng();
                        byte[] md5hash = cng.ComputeHash(System.IO.File.ReadAllBytes(path));

                        //worker w = (worker)a.CreateInstance(o.FullName);
                        string hash = Encoding.Unicode.GetString(md5hash);


                        man.Cache.Sql("insert or replace into workers(path,type,hash) values('" + path + "','" + o.FullName + "','" + hash + "')", false);
                        // w.info.md5hash= 
                        //man.Cache.Sql("
                        //workers.Add(w);

                    }
                }
                //   this.ToString();
                //   if(a.DefinedTypes[0]!=null&&a.DefinedTypes[0]
            }
        }
        private string[] select_column_from_sqlite(string tablename, string columnname) 
        {
            List<string> list = new List<string>();
            object[] temp = man.Cache.Sql("select "+columnname+" from "+tablename, true);
            foreach (object o in temp)
            {
                list.Add(Convert.ToString(o));
            }
            return list.ToArray();
        }
        public string[] KnownWorkers
        {
            get
            {
                return select_column_from_sqlite("workers", "type");
            }
        }
        public string[] RegisteredManagers 
        {
            get
            {
                return select_column_from_sqlite("managers", "name");
            }
        }
        public void register(managerinfo info,string workertype="") 
        {
            man.Cache.Sql(
                "replace into managers(name,address,port,opcode,workertype,dbfilename,dbtablename) " +
                "values(" +
                "'" + info.managername + "'," +
                "'" + info.address.ToString() + "'," +
                "'" + ((int)info.port).ToString() + "'," +
                "'" + info.able_to_accept.ToString() + "'," +
                "'" + workertype + "'," +
                "'" + info.filename + "'," +
                "'" + info.tablename + "')"
                ,false);
        }
        public List<async_cached_manager> init_managers(string[] managernames) 
        {
            List<async_cached_manager> managers = new List<async_cached_manager>();
            foreach (string s in managernames)
            {
                managerinfo info = minfo(s);
                async_cached_manager temp_man = null;
                if (info.managername == "null") continue;
                else
                {
                    object[] temp = man.Cache.Sql("select workertype from managers where name='" + s + "'", true);
                    if (temp[0] is System.DBNull)continue;

                    string workertype = Convert.ToString(temp[0]);

                    temp = man.Cache.Sql("select path from workers where type ='" + workertype + "'", true);
                    string workerpath = Convert.ToString(temp[0]);
                    //try{
                    Assembly a = Assembly.LoadFrom(workerpath);
                    worker w = (worker)a.CreateInstance(workertype);
                    w.Name = info.managername;
                    w.opcode = info.able_to_accept;
                    workers.Add(w);
                    managers.Add(new async_cached_manager(info, workers.Last(), false));
                    
                    //}
                    //catch(Exception e){}

                }
            }
            return managers;
        }
        

        

       
    }
}
